﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace LcfContols
{

    public class LDataGridView : DataGridView
    {

        #region 事件
        /// <summary>
        /// 翻页事件
        /// </summary>
        public event Action<LDataGridView> PageChange;
        /// <summary>
        /// 显示下拉事件
        /// </summary>
        public event Action<DataGridViewRow,DataGridViewPanelRow> ItemShow;

        /// <summary>
        /// 滚动到底部事件
        /// </summary>
        public event Action<LDataGridView> VScroll_End;
        #endregion

        #region 变量

        /// <summary>
        /// 绘制分页控件
        /// </summary>
        private bool _drawPageInfo = true;

        /// <summary>
        /// 数据显示区域最小高度
        /// </summary>
        private int _minHeight = 200;

        /// <summary>
        /// 不显示加载动画
        /// </summary>
        private bool _noLoading = false;

        /// <summary>
        /// 显示底部信息
        /// </summary>
        private bool _showFooter = true;

        /// <summary>
        /// 滚动到底部时是否已经重绘了底部控件
        /// </summary>
        private bool _reloadFooter = false;

        /// <summary>
        /// 间隔颜色
        /// </summary>
        private bool _rowColor = true;
        #endregion

        #region 附加控件

        /// <summary>
        /// 底部控件
        /// </summary>
        private LDataGridViewSumRow _footer;

        /// <summary>
        /// 分页控件
        /// </summary>
        private PageInfo pageInfo;

        /// <summary>
        /// 加载提示
        /// </summary>
        private Loading _loading = new Loading();
        #endregion

        #region 属性
        
        /// <summary>
        /// 分页数据
        /// </summary>
        public Page Page
        {
            get
            {
                return pageInfo.Page;
            }
            set
            {
                pageInfo.Page = value;
            }
        }

        /// <summary>
        /// 间隔颜色
        /// </summary>
        public bool RowColor {
            get
            {
                return _rowColor;
            }
            set
            {
                _rowColor = value;
            }
        }

        /// <summary>
        /// 隐藏分页控件
        /// </summary>
        public bool HidePage { get; set; }

        /// <summary>
        /// 数据显示区最小高度，如果整体空间小于该高度，底部分页自动隐藏
        /// </summary>
        public int MinHeight { get { return _minHeight; } set { _minHeight = value; } }

        /// <summary>
        /// 加载文字
        /// </summary>
        public string LoadingMessage
        {
            get
            {
                return _loading.Text;
            }
            set
            {
                _loading.Text = value;
            }
        }

        /// <summary>
        /// 是否显示加载动画
        /// </summary>
        public bool NoLoading{
            get
            {
                return _noLoading;
            }
            set
            {
                _noLoading = value;
            }
        }

        /// <summary>
        /// 加载动画的图片
        /// </summary>
        public Image LoadingImage
        {
            get
            {
                return _loading.Image;
            }
            set
            {
                _loading.Image = value;
            }
        }

        #endregion

        #region 统计

        /// <summary>
        /// 显示底部统计行
        /// </summary>
        public bool ShowSummery
        {
            get
            {
                return _showFooter;
            }
            set
            {
                _showFooter = value;
            }
        }

        /// <summary>
        /// 要统计的列的索引集合
        /// </summary>
        public int[] SumColumnIndexs
        {
            get { return _footer.sumColumnsIndex; }
            set { _footer.sumColumnsIndex = value; }
        }

        /// <summary>
        /// 各列的统计结果，用来手工写入统计结果
        /// </summary>
        public Dictionary<int,decimal> SumColumns
        {
            get
            {
                return _footer.ColumnsSum;
            }
        }

        /// <summary>
        /// 单元格修改结束后是否自动更新统计数
        /// </summary>
        public bool CellEndEditUpdateSummery
        {
            get
            {
                return _footer.CellEndEditUpdateSummery;
            }
            set
            {
                _footer.CellEndEditUpdateSummery = value;
            }
        }

        /// <summary>
        /// 统计数据
        /// <param name="update">直接更新数据而不是从列表中进行动态统计</param>
        /// </summary>
        public void Summery(bool update=false)
        {
            _footer.Summery(update);
        }

        #endregion

        #region 点击下拉显示详细

        /// <summary>
        /// 点击显示下拉项目
        /// </summary>
        public bool ShowItem
        {
            get;
            set;
        }

        #endregion

        public LDataGridView()
        {
            SetStyle(
                //ControlStyles.UserPaint | // 控件将自行绘制，而不是通过操作系统来绘制  
                ControlStyles.OptimizedDoubleBuffer | // 该控件首先在缓冲区中绘制，而不是直接绘制到屏幕上，这样可以减少闪烁,开启情况下更改列宽度中的显示效果会消失
                ControlStyles.AllPaintingInWmPaint | // 控件将忽略 WM_ERASEBKGND 窗口消息以减少闪烁  
                ControlStyles.ResizeRedraw | // 在调整控件大小时重绘控件 
                ControlStyles.SupportsTransparentBackColor,// 控件接受 alpha 组件小于 255 的 BackColor 以模拟透明
                true // 设置以上值为 true 
                );
            _loading.BackColor = SystemColors.Control;
            Controls.Add(_loading);
            _loading.Visible = false; //开始先不显示加载动画
            pageInfo = new PageInfo(this);
            pageInfo.Tag = this;
            pageInfo.ShowTopLine = true;
            pageInfo.pgChange += PageInfo_pgChange;
            ///底部信息
            _footer = new LDataGridViewSumRow(this);
            _footer.HScrollSet((HScrollBar)HorizontalScrollBar);
        }

        protected override void OnRowHeaderMouseClick(DataGridViewCellMouseEventArgs e)
        {
            if (ShowItem){
                DataGridViewRow clickRow = Rows[e.RowIndex];
                if(!(clickRow is DataGridViewPanelRow))
                {
                    DataGridViewPanelRow showRow;
                    if (e.RowIndex < Rows.Count - 1) //判断是否是最后一行
                    {
                        DataGridViewRow nextRow = Rows[e.RowIndex + 1];
                        if (nextRow is DataGridViewPanelRow)
                        {
                            showRow = nextRow as DataGridViewPanelRow;
                            showRow.Visible = !showRow.Visible;
                            base.OnRowHeaderMouseClick(e);
                            return;
                        }
                    }
                    showRow = new DataGridViewPanelRow();
                    showRow.SetVScrollBar(VerticalScrollBar);
                    if (ItemShow != null){
                        ItemShow(clickRow, showRow);
                    }
                    Rows.Insert(e.RowIndex + 1, showRow); //插入
                }
            }
            base.OnRowHeaderMouseClick(e);
        }

        protected override void OnParentChanged(EventArgs e)
        {
            if(pageInfo.Parent != null) //修改所在的控件后，底部控件也跟随改变
                pageInfo.Parent.Controls.Remove(pageInfo);
            if (_footer != null && _footer.Parent != null)
                _footer.Parent.Controls.Remove(_footer); //底部区域移除
            base.OnParentChanged(e);
        }

        /// <summary>
        /// 出发更新页面事件
        /// </summary>
        private void PageInfo_pgChange()
        {
            if (PageChange != null)
                PageChange(this);
        }

        /// <summary>
        /// 开始加载数据
        /// 主要用来清理当前页面的所有数据，然后禁用分页功能
        /// </summary>
        public void StartLoadingData()
        {
            foreach(DataGridViewRow row in Rows)
            {
                if (row is DataGridViewPanelRow && row.HeaderCell.Value != null) //入果时扩展行，则移除扩展行中的控件
                    Controls.Remove((Control)row.HeaderCell.Value); //移除这个控件
            }
            Rows.Clear();
            pageInfo.Enabled = false;
            if (!_noLoading)
                _loading.Visible = true;
        }

        /// <summary>
        /// 清空分页数据
        /// </summary>
        public void PageClear()
        {
            pageInfo.Clear();
        }

        /// <summary>
        /// 数据加载结束
        /// 隐藏加载动画，启用分页
        /// </summary>
        public void EndLoadingData()
        {
            pageInfo.Enabled = true;
            pageInfo.UpdatePage(); //更新底部页面
            pageInfo.UpdateNowRows(Rows.Count); //更新单页信息
            _loading.Visible = false;
        }

        #region 让底部控件跟随变化

        protected override void OnDragDrop(DragEventArgs drgevent)
        {
            base.OnDragDrop(drgevent);
            NCPaint(); //位置变化，更新移动底部区域
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            NCPaint(); //位置变化，更新移动底部区域
        }

        protected override void OnLocationChanged(EventArgs e)
        {
            base.OnLocationChanged(e);
            NCPaint(); //位置变化，更新移动底部区域
        }

        protected override void OnScroll(ScrollEventArgs e)
        {
            base.OnScroll(e);
            if (e.ScrollOrientation == ScrollOrientation.VerticalScroll)
            {
                if (e.NewValue + DisplayedRowCount(false) == Rows.Count)
                {
                    if (VScroll_End != null){ //触发滚动到底数据
                        VScroll_End(this);
                    }
                    if (!_reloadFooter)
                    {
                        NCPaint(); //重绘底部控件,防止最后一条数据被遮挡
                        _reloadFooter = true;
                    }
                }
            }
        }

        #endregion

        #region 隔行显示不同颜色

        protected override void OnRowStateChanged(int rowIndex, DataGridViewRowStateChangedEventArgs e)
        {
            base.OnRowStateChanged(rowIndex, e);
            if (_rowColor)
            {
                if (rowIndex < 0 || rowIndex >= Rows.Count)
                    return;
                bool lightGray = false;
                if (rowIndex > 0) //获取该行上一显示行的颜色是不是深色
                    for (int i = rowIndex - 1; i >= 0; i--)
                        if (Rows[i].Displayed && Rows[i].Visible)
                        {
                            lightGray = Rows[i].DefaultCellStyle.BackColor == Color.LightGray;
                            break;
                        }
                for (int i = rowIndex; i < Rows.Count; i++) //后面的每一行都和上一行颜色不一样
                    if (Rows[i].Displayed && Rows[i].Visible)
                    {
                        Rows[i].DefaultCellStyle.BackColor = lightGray ? RowTemplate.DefaultCellStyle.BackColor : Color.LightGray;
                        lightGray = !lightGray;
                    }
            }
            _footer.Summery();
        }

        #endregion

        protected override void DefWndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case (int)WinMsg.WM_NCPAINT:
                    NCPaint();
                    break;
                case (int)WinMsg.WM_NCCALCSIZE:
                    if (m.LParam != IntPtr.Zero )
                    {
                        int minHeight = pageInfo.Height + 1 + _minHeight;
                        if (m.WParam.ToInt32() == 1)
                        {
                            NCCALCSIZE_PARAMS csp = (NCCALCSIZE_PARAMS)m.GetLParam(typeof(NCCALCSIZE_PARAMS));
                            _drawPageInfo = csp.rgrc[0].bottom - csp.rgrc[0].top > minHeight;
                            if (_drawPageInfo)
                            {
                                if(!HidePage)
                                    csp.rgrc[0].bottom -= pageInfo.Height;
                                Marshal.StructureToPtr(csp, m.LParam, true);
                                m.Result = IntPtr.Zero;
                            }
                        }
                        else
                        {
                            RECT rc = (RECT)m.GetLParam(typeof(RECT));
                            _drawPageInfo = rc.bottom - rc.top > minHeight;
                            if (_drawPageInfo)
                            {
                                if(!HidePage)
                                    rc.bottom -= pageInfo.Height;
                                Marshal.StructureToPtr(rc, m.LParam, true);
                                m.Result = IntPtr.Zero;
                            }
                        }
                    }
                    pageInfo.Visible = _drawPageInfo && !HidePage; //分页控件是否显示
                    _footer.Visible = _drawPageInfo && ShowSummery; //统计行是否显示
                    break;
            }
            base.DefWndProc(ref m);
        }

        /// <summary>
        /// 设置分页控件属性
        /// </summary>
        private void initializeControl()
        {
            pageInfo.Width=Width-2;
            pageInfo.BackColor = BackColor;
            pageInfo.Font = Font;
            pageInfo.Location = new Point(Left + 1, Bottom - pageInfo.Height - 1);
            if (Parent != null && !Parent.Contains(pageInfo))
            {
                Parent.Controls.Add(pageInfo);
                Parent.Controls.SetChildIndex(pageInfo, Parent.Controls.GetChildIndex(this)); //将底部显示的控件顺序放到本控件的前一位。是的底部控件正好可以遮挡到本控件的底部
            }
        }

        /// <summary>
        /// 底部绘制
        /// </summary>
        private void NCPaint()
        {
            //Todo:最后一行遮挡问题还是不行,可能会显示空白行出来
            VScroll_VisibleChanged(null, null);
            if (!_noLoading){ //移动加载动画的位置
                _loading.Location = new Point(ClientRectangle.Left + (ClientRectangle.Width - _loading.Width) / 2, ClientRectangle.Top + (ClientRectangle.Height - _loading.Height) / 2);
            }
            if(_drawPageInfo)
            {
                if (!HidePage)
                    initializeControl();
                if (_showFooter)
                    initializeFooterControl();
                IntPtr hdc = Win32API.GetWindowDC(Handle);
                using (Graphics g = Graphics.FromHdc(hdc))
                { 
                    Pen pen = SystemPens.WindowText;
                    g.DrawLine(pen, 0, ClientRectangle.Height, 0, Height); //左侧的线
                    g.DrawLine(pen, 0, Height - 1, Width, Height - 1); //底部线
                    g.DrawLine(pen, Width - 1, ClientRectangle.Height, Width - 1, Height - 1); //右侧线
                    Rectangle bottomRect = new Rectangle(1, ClientRectangle.Height, Width - 2, Height - ClientRectangle.Height - 1);
                    g.FillRectangle(SystemBrushes.Control, bottomRect);
                }
                Win32API.ReleaseDC(Handle, hdc);
            }
        }

        #region 底部统计控件位置确定

        /// <summary>
        /// 新增的一行数据
        /// </summary>
        private DataGridViewRow addrow;

        private void VScroll_VisibleChanged(object sender, EventArgs e)
        {
            if (addrow != null && Rows.Contains(addrow))
            {
                Rows.Remove(addrow);
                addrow = null;
            }
            if (!_footer.Visible)
                return;
            if (VerticalScrollBar.Visible && _footer.Visible)
            {
                try
                {
                    addrow = Rows[Rows.Add()];
                }catch(Exception)
                {

                }
            }
        }

        public void initializeFooterControl()
        {
            if (!Controls.Contains(_footer)){
                Controls.Add(_footer);
                _footer.SendToBack();
            }
            _footer.Left = 1;
            _footer.Width = ClientRectangle.Width-(VerticalScrollBar.Visible?VerticalScrollBar.Width:0)-2;
            int height = ColumnHeadersHeight;
            int showRows = DisplayedRowCount(false); //获取显示的函数
            if(showRows > 0)
            {
                int firstrowindex = FirstDisplayedCell.RowIndex; //获取显示的第一行的下标
                for (int i = 0; i < showRows; i++){
                    height += Rows[firstrowindex + i].Height;
                }
                int h= ClientRectangle.Height- (HorizontalScrollBar.Visible ? HorizontalScrollBar.Height + 1 : 0);
                if((h - height) < RowTemplate.Height)
                {
                    _footer.Height = h - height + RowTemplate.Height;
                    _footer.Top = ClientRectangle.Top + height - RowTemplate.Height;
                    return;
                }
            }
            _footer.Top = ClientRectangle.Bottom - (HorizontalScrollBar.Visible ? HorizontalScrollBar.Height + 1 : 0) - _footer.Height;
            _footer.Height = RowTemplate.Height;
        }

        /// <summary>
        /// 行高度调整后调整底部控件的位置
        /// </summary>
        /// <param name="e"></param>
        protected override void OnRowHeightChanged(DataGridViewRowEventArgs e)
        {
            base.OnRowHeightChanged(e);
            initializeFooterControl();
        }

        #endregion
        
    }
}